上一篇我們已經學會運用序列以及篩選的方式來準確定位,但除此之外,我們還可能遇到畫面上沒有文字(無法用 getByRole
或 getByText
),也沒有 label (無法用 getByLebel
),標籤內更沒有屬性,面對這種令人頭痛的怪物(元素),我們該怎麼定位呢?
首先,如果 html 結構較單純,同樣可以使用上一篇介紹的序列定位或是篩選方式取得元素位置,但若是結構比較複雜,前面認識的定位方法已無法定位到想要的目標,就必須使用其他方式來定位,我們可以嘗試用這兩種方式來定位:
依靠 「有文字或明顯屬性」的鄰居定位,也就是先定位到可辨識的元素,再利用父子/兄弟關係查找該元素。
使用 XPath 表達式定位,這是一種將網頁上每一個元素、文字、屬性,甚至是注釋都視為一個節點的定位方式,並且以路徑的方式表達,關於 XPath 更詳細的說明可以參考:XPath 入門指南:輕鬆理解網頁數據抓取。
不多說,我們直接進入猶如初階副本的挑戰,運用上面第一種方式在 開放博物館 - 國家寶藏 這個尋寶遊戲網站中闖關,成功找出所有寶物吧!
難易度 ★☆☆☆☆
看起來非常簡單,只需要鎖定「中文版」的文字就能點擊目標元素:
await page.getByText('中文版').click();
📜破關秘笈:
必須特別注意,點擊中文版後,無法確定需要等多久時間畫面才準備完成,所以加上{ waitUntil: 'load' }
等待畫面完成,否則直接執行後續動作,會超過 timeout 導致測試失敗。
難易度 ★★☆☆☆
這個箭頭是一張圖片,alt
是空字串,所以無法使用 page.getByRole('img', { name: alt })
來找到它,雖然有來源 src
,可以使用 CSS 屬性選擇器定位,但會變得很冗長,不易閱讀,且如果圖片來源更換,測試就會壞掉,如此,最適合的方式是先選擇這張圖片的父元素<span>
,再往子元素選擇:
await page.locator('span[class="open--next"] > img').click();
難易度 ★★★☆☆
這一關,並不如畫面上這麼簡單,只需要點擊文字即可過關,如果用getByText()
定位,那麼會得到超過 timeout 還找不到元素的結果,為什麼會這樣呢?我們打開 devtool 查看:
會發現它是偽元素並非真實的元素,不存在於 DOM 當中,因此 Playwright 無法操作,這時,我們定位它的父元素,但定位在父元素<div class="open--card open--card-1" style="top: -10px;"></div>
仍然找不到,因此只能再往上一層找,終於能成功點擊啦!
await page.locator('div[class="open--dialog open--dialog-2"]').click();
難易度 ★★☆☆☆
這一關的怪物狀態與第 2 關向下箭頭相同,相信各位玩家已經駕輕就熟,先選擇父元素,再選擇圖片:
await page.locator('#tr4-1 > img').click();
恭喜!我們找到第一個寶物了!!!
完整程式碼:
import { test, expect } from '@playwright/test';
test('find the all treasure', async ({ page }) => {
// 第 1 關:進入首頁,點擊中文版
await page.goto('https://openmuseum.tw/treasure');
await expect(page.getByRole('link', { name: '中文版' })).toBeVisible();
await page.getByText('中文版').click();
await page.waitForURL('**/main?lang=zh-Hant', { waitUntil: 'load' });
await expect(page.getByText('山壑間的國家寶藏').nth(1)).toBeVisible();
// 第 2 關:點擊向下箭頭
await page.locator('span[class="open--next"] > img').click();
// 第 3 關:點擊說明文字
await page.locator('div[class="open--dialog open--dialog-2"]').click();
await page.locator('div[class="open--dialog open--dialog-3"]').click();
await page.locator('div[class="open--dialog open--dialog-4"]').click();
// 第 4 關:找出第一個寶物
await page.locator('#tr4-1 > img').click();
})
執行結果:
難易度 ★★★★☆
最後這一關,就留給各位玩家動動腦啦 ~ 同時,也可以嘗試將元素定位方式改成 XPath 唷!
如何快速地找出所有寶物,是測試時很重要的策略,這樣才能在有限的時間與資源裡,取得最高的測試效益。
到這裡,我們透過尋寶遊戲網站,學會了如何鎖定沒有「真名」的怪物,定位到想攻擊的目標,接下來,下一個初階副本任務是檔案上傳與下載,同樣經由實戰的方式,讓你進一步擴展測試的攻擊範圍與驗證深度。